/*
 * StandardCmdBar.java
 *
 * Created on 28 October 2007, 21:59
 *
 */

package net.ubinow.mflex.widgets;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

import net.ubinow.mflex.baseui.ICommandBar;
import net.ubinow.mflex.baseui.WFont;
import net.ubinow.mflex.events.AbsEventPublisher;
import net.ubinow.mflex.events.Event;
import net.ubinow.mflex.events.EventFactory;
import net.ubinow.mflex.util.Constants;
import net.ubinow.mflex.util.KeyConstants;
import net.ubinow.mflex.util.MiscUtil;



/**
 * standard command bar with left and right commands
 * TODO: add command bar font (to allow different fonts to be used)
 * @author Josh
 */
public class StandardCmdBar extends AbsEventPublisher implements ICommandBar {
    
    public static final int PANEL_DOCKING_SIDES     = 0;
    public static final int PANEL_DOCKING_CENTRE    = 1;
    
    private Image _cmdBar = null;
    private Image _cmdPanel = null;
    private Image _highlight = null;
    private Image _selGfx = null; // graphic to show what command is currently selected
    
    ///
    // 'all' command fields
    ///
    public Image _cmdIconsStrip = null;
    public int _cmdIconW = 0; // command icon width
    public int _cmdIconH = 0; // command icon height
    
    public int[] _cmdIDs = null;
    public String[] _cmdLabels = null;
    
    ///
    // 'current' command fields
    ///
    private int[] _leftCmds 	= null;
    private int _leftCmdsCnt	= 0; // keeps a reference to the actual size of the commands
    private int[] _rightCmds	= null;
    private int _rightCmdsCnt = 0; // keeps a reference to the actual size of the commands
    private int _selIndex = 0;
    
    // position of docked command bar
    private int _x = 0;
    private int _y = 0;
    
    private String _id = Constants.UNDEFINED;
    private int _width = 0;
    private int _height = 0;
    private int _bgColour = -1;
    
    ///
    // 'working' variables
    ///
    private int _rightMenuX = 0; // horizontal left position of the right menu bar
    private int _rightTextX = 0; // horizontal position of the right menu command text
    
    private int _curMenuY = 0; // position of the top of the 'opening' command bar
    private int _menuY    = 0; // position of the top of the 'opened' command bar
    
    private int _selectedSide = -1; // -1 to indicate that neither is selected else CMD_LEFT and CMD_RIGHT respectively
    
    private int _leftCmdHeight = 0; // worked out each time the initCmd button is called for the right commands
    private int _rightCmdHeight = 0; // worked out each time the initCmd button is called for the right commands
    
    private WFont _fntCmdBar = null;
    private WFont _fntCmds   = null;
    private int _fontY = 0;
    
    private boolean _isVisible = true;
    private boolean _enabled = true; 
    
    private int _curState = VIEWING_STATE_DOCK;
    private int _prevState = -1;
    
    private int _cmdPanelDocking = PANEL_DOCKING_SIDES;
    
    private MiscUtil _miscUtils = null;
    
    public StandardCmdBar( Image cmdBar, Image cmdPanel, Image hl, Image selGfx, int[] cmdIDs,
            String[] cmdLabels, Image cmdIconsStrip, int cmdIconW, int cmdIconH, WFont font ){
        
        _cmdBar = cmdBar;
        _cmdPanel = cmdPanel;
        _highlight = hl;
        _selGfx = selGfx;
        _cmdIDs = cmdIDs;
        _cmdLabels = cmdLabels;
        _cmdIconsStrip = cmdIconsStrip;
        _cmdIconW = cmdIconW;
        _cmdIconH = cmdIconH;
        _fntCmdBar = _fntCmds = font;
        
        _miscUtils = MiscUtil.getInstance();
        
        init();
    }
    
    private void init(){
        _isVisible = true;
        _enabled = true; 
        _curState = VIEWING_STATE_DOCK;
        _prevState = -1;
        _selectedSide = CMD_NONE;
        
        if( _cmdBar != null ){
            _height = _cmdBar.getHeight();
            _width = _cmdBar.getWidth();
        }
        
        // default y value
        _menuY = _curMenuY = _y = Constants.MISC_SCREEN_HEIGHT-_height;
        if( (Constants.MISC_SCREEN_WIDTH-_width) > 0 ){
            _x = (Constants.MISC_SCREEN_WIDTH-_width)>>1;
        } else{
            _x = 0;
        }
        
        _leftCmds = new int[_cmdIDs.length];
        _leftCmdsCnt = 0;
        _rightCmds = new int[_cmdIDs.length];
        _rightCmdsCnt = 0;
        
    }
    
    //<editor-fold defaultstate="collapsed" desc="implementation of ICommandBar">
    
    public void show( int side ) {
        if( isShowing() )
            return;
        
        _selectedSide = side;
        _selIndex = 1;
        _curMenuY = _y;
        
        if( _selectedSide == CMD_LEFT ){
            _menuY = _y-_leftCmdHeight;
        } else{
            _menuY = _y-_rightCmdHeight;
        }
        _curState = VIEWING_STATE_SHOW;
    }
    
    public void dock() {
        _prevState = _curState;
        _curState = VIEWING_STATE_DOCK;        
        _menuY = _y;
    }
    
    public boolean isShowing() {
        if( _selectedSide != CMD_NONE && _curMenuY == _menuY ){
            return true;
        }
        else{
            
            return false;
        }
    }
    
    public boolean isDocked() {
        
        if( _selectedSide == CMD_NONE && _curMenuY == _y )
            return true;
        else
            return false;
    }
    
    public void initCommands(int[] leftCmdIDs, int[] rightCmdIDs) {
        initCommands( CMD_LEFT, leftCmdIDs );
        initCommands( CMD_RIGHT, rightCmdIDs );
    }
    
    /**
     * nb: the item at index 0 will be the item that is displayed at the command bars text
     **/
    public void initCommands(int side, int[] cmdIDs) {
        if( side == CMD_LEFT ){
            if( cmdIDs == null ){
                _leftCmdsCnt = 0;
            } else{
                _leftCmdsCnt = cmdIDs.length;
                _leftCmdHeight = CMD_PADDING_TOP;
                for( int i=0; i<_leftCmdsCnt-1; i++ ){
                    _leftCmds[i] = cmdIDs[i];
                    
                    // work out height
                    _leftCmdHeight += CMD_PADDING_Y+_fntCmds.getHeight();
                }
            }
        } else if( side == CMD_RIGHT ){
            if( cmdIDs == null ){
                _rightCmdsCnt = 0;
            } else{
                _rightCmdsCnt = cmdIDs.length;
                _rightCmdHeight = CMD_PADDING_TOP;
                for( int i=0; i<_rightCmdsCnt-1; i++ ){
                    _rightCmds[i] = cmdIDs[i];
                    
                    // work out height
                    _rightCmdHeight += CMD_PADDING_Y+_fntCmdBar.getHeight();
                }
            }
        }
    }
    
    public void initCommand(int side, int cmdID) {
        initCommands( side, new int[]{ cmdID } );
    }
    
    public void addCommand(int side, int cmdID) {
        // TODO: implement this
    }
    
    public void insertCommand(int side, int cmdID, int index) {
        // TODO: implement this
    }
    
    public void removeCommand(int side, int cmdID) {
        // TODO: implement this
    }
    
    public void enabled( boolean enable ){
        _enabled = enable;
    }
    
    public boolean isEnabled(){
        return _enabled;
    }
    
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="implements of IWidget">
    
    public int maxLayers(){
        return 1; 
    }            
    
    public String getID() {
        return _id;
    }
    
    public void setID(String id) {
        _id = id;
    }
    
    public int getX() {
        return _x;
    }
    
    public void setX(int x) {
        _x = x;
    }
    
    public int getY() {
        return _y;
    }
    
    public void setY(int y) {
        _y = y;
        
        _curMenuY = _menuY = _y;
        
        // work out where the text should sit
        if( _fntCmdBar != null )
            _fontY = (_y+8);
        else
            _fontY = y;
    }
    
    public void setPos( int x, int y ){
        _x = x;
        setY( y );
    }
    
    public void setOrgPos( int x, int y ){
        System.out.println("Not supported - StandardCmdBar.setOrgPos");
    }
    
    public void resetPos(){
        System.out.println("Not supported - StandardCmdBar.resetPos");
    } 
    
    public int getOrgX(){
       System.out.println("Not supported - StandardCmdBar.getOrgX");
       return -1;
    }
    public int getOrgY(){
        System.out.println("Not supported - StandardCmdBar.getOrgY");
        return -1;
    }
    
    public int getWidth() {
        return _width;
    }
    
    public void setWidth(int w) {
        _width = w;
    }
    
    public int getHeight() {
        return _height;
    }
    
    public void setHeight(int h) {
        _height = h;
    }
    
    public int getPaddingW() {
        // not implemented
        return 0;
    }
    
    public void setPaddingW(int padding) {
        // not implemented
    }
    
    public int getPaddingH() {
        // not implemented
        return 0;
    }
    
    public void setPaddingH(int padding) {
        // not implemented
    }
    
    public void setBG(Image bg) {
        _cmdBar = bg;
    }
    
    public void setBG(int colour) {
        _bgColour = colour;
    }
    
    /** sets the command bar font **/
    public void setFont( WFont font) {
        _fntCmdBar = font;
    }
    
    /** retrieves the command bar font **/
    public WFont getFont() {
        return _fntCmdBar;
    }
    
    /** sets the command bar font **/
    public void setCommandFont(WFont font) {
        _fntCmds = font;
    }
    
    /** retrieves the command bar font **/
    public WFont getCommandFont() {
        return _fntCmds;
    }
    
    public boolean isVisible() {
        return _isVisible;
    }
    
    public void setIsVisible( boolean visible ){
        _isVisible = visible;
    }
    
    public int getTotalHeight() {
        return getHeight();
    }

    public int getTotalWidth() {
        return getWidth();
    }

    public boolean isSelectable() {
        return false; 
    }

    public void setFocus(boolean focus,int direction) {
        
    }
    
    public boolean isAnimated(){
        return false; 
    }
    
    public int getBottomY() {
        return _y+_height;
    }
    
    public int getBottomY( boolean includeHeight ) {
        return getBottomY();
    }

    public boolean supportsTransitioning() {
        return false; 
    }
    
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="getters and setters">
    
    /**determines where the command panel is aligned to when opened **/
    public int getCmdPanelDocking(){
        return _cmdPanelDocking; 
    }
    
    /**determines where the command panel is aligned to when opened **/
    public void setCmdPanelDocking( int dock ){
        _cmdPanelDocking = dock;
    }
    
    //</editor-fold>
    
    public void cycle() {
        // if transitioning up
        if( !isShowing() && _curState == VIEWING_STATE_SHOW ){            
            _curMenuY += MiscUtil.getInstance().calcHalfDistance( _menuY, _curMenuY );            
            
            if( _curMenuY < _menuY ){
                _curMenuY = _menuY;
            }
        }
        
        // else if transitioning down
        else if( !isDocked() && _curState == VIEWING_STATE_DOCK ){
            _curMenuY += MiscUtil.getInstance().calcHalfDistance( _menuY, _curMenuY );
            
            if( _curMenuY >= _y ){
                _curMenuY = _y;
                _selectedSide = CMD_NONE;
                _selIndex = 1;                
            }
        }
    }
    
    public void paint(Graphics g, int offsetX, int offsetY, int layer ) {
        if( !_isVisible )
            return;
        
        // TODO: is cropping the screen necessary
        
        // paint commands background and commands if is in transition or displaying
        if( !isDocked() ){
            int x = 0;
            int[] cmdIDs = null;
            int size = 0;
            
            if( _selectedSide == CMD_LEFT ){
                if( _cmdPanelDocking == PANEL_DOCKING_SIDES )
                    x = Constants.AD_CMD_BAR_CMDS_TEXT_PADDING_H;
                else if( _cmdPanelDocking == PANEL_DOCKING_CENTRE )
                    x = ((_cmdBar.getWidth()-_cmdPanel.getWidth())>>1);
                
                cmdIDs = _leftCmds;
                size = _leftCmds.length;
            } else{
                if( _cmdPanelDocking == PANEL_DOCKING_SIDES )
                    x = Constants.MISC_SCREEN_WIDTH - (_cmdPanel.getWidth() + Constants.AD_CMD_BAR_CMDS_TEXT_PADDING_H);
                else if( _cmdPanelDocking == PANEL_DOCKING_CENTRE )
                    x = ((_cmdBar.getWidth()-_cmdPanel.getWidth())>>1);
                    
                cmdIDs = _rightCmds;
                size = _rightCmds.length;
            }
            
            int y = _curMenuY;
            
            // draw commands panel
            int cmdPanelH = Constants.MISC_SCREEN_HEIGHT - _curMenuY;
            if( _cmdPanel.getHeight() < cmdPanelH ){
                _miscUtils.drawImageByTiling( g, _cmdPanel, offsetX+x, offsetX+x+_cmdPanel.getWidth(), 
                        offsetY+_curMenuY, offsetY+_curMenuY+cmdPanelH, 10, 10 );
            }
            else{
                g.drawImage( _cmdPanel, offsetX+x, offsetY+_curMenuY, Constants.GFX_ALIGN_TOP_LEFT );
            }
            
            // print all commands
            y += CMD_PADDING_TOP; 
            for( int i=1; i<size; i++ ){                                
                
                if( isShowing() && i == _selIndex && _highlight != null ){
                    // paint highlight and selection icon if displaying                            
//                    g.setColor( Constants.AD_COLOUR_HIGHLIGHT );
//                    g.fillRect(  offsetX+  CMD_PADDING_X + x, 
//                            y - (Constants.AD_HIGHLIGHT_PADDING_Y<<1), 
//                            _cmdPanel.getWidth()-(Constants.AD_HIGHLIGHT_PADDING_X<<1), 
//                            _fntCmds.getHeight() + CMD_PADDING_Y );
                    
                    g.drawImage( _highlight, offsetX+CMD_PADDING_X+x, y, Constants.GFX_ALIGN_TOP_LEFT );
                }
                
                _fntCmds.drawString( g, _cmdLabels[_cmdIDs[i]], offsetX+CMD_PADDING_X+x, y );
                // TODO: draw selected gfx
                
                y += _fntCmds.getHeight() + CMD_PADDING_Y;
                
                if( y > _y )                          
                    break;
            }
        }
        
        paintCommandBar( g, offsetX, offsetY );        
    }
    
    private void paintCommandBar( Graphics g, int offsetX, int offsetY ){                
        
        // paint command bar
        g.drawImage( _cmdBar, _x + offsetX, _y + offsetY, Constants.GFX_ALIGN_TOP_LEFT );
        
        // if transitioning down but have not yet docked then return as we dont want to display any commands 
        // in this state 
        if( _curState == VIEWING_STATE_DOCK && !isDocked() )
            return;
        
        // only draw the labels of the commaand bar if the command bar is enabled - our way of communicating with the user to say that the commandbar
        // is disabled 
        if( !_enabled )
            return; 
        
        // paint options on command bar
        if( isDocked() ){
            // left side
            if( _leftCmdsCnt > 0 ){
                String label = _cmdLabels[_leftCmds[0]];
                _fntCmdBar.drawString( g, label, offsetX+Constants.AD_CMDS_BAR_BG_PADDING_H, offsetY+_fontY );
            }
            
            // right side
            if( _rightCmdsCnt > 0 ){
                String label = _cmdLabels[ _rightCmds[0] ];
                
                _fntCmdBar.drawString( g, label,
                        offsetX+getWidth()-_fntCmdBar.stringWidth(label),
                        offsetY+_fontY );       
            }
            
        } else{
            _fntCmdBar.drawString( g, Constants.AD_CMD_TEXT_LEFT, offsetX+Constants.AD_CMDS_BAR_BG_PADDING_H, offsetY+_fontY );
            _fntCmdBar.drawString( g, Constants.AD_CMD_TEXT_RIGHT,
                    offsetX+getWidth()+Constants.AD_CMDS_BAR_BG_PADDING_H-_fntCmdBar.stringWidth(Constants.AD_CMD_TEXT_RIGHT),
                        offsetY+_fontY );                                          
        }
    }
    
    public boolean handleKeyPressed(int action, int keyCode) {
        if( !_enabled )
            return false; 
        
        // ignore key if docked or in transition and not left or right softkey
        if( isDocked() && !(keyCode == KeyConstants.LEFT_SOFT_BUTTON || keyCode == KeyConstants.RIGHT_SOFT_BUTTON ) )
            return false;        
        // if docked then execute command if only one command exists else open command menu
        if( isDocked() && (keyCode == KeyConstants.LEFT_SOFT_BUTTON || keyCode == KeyConstants.RIGHT_SOFT_BUTTON ) ){
            return keyPressedDocked( action, keyCode );
        }
        
        if( isShowing() ){
            return keyPressedShowing( action, keyCode );
        }
        
        return false;
    }
    
    private boolean keyPressedShowing( int action, int keyCode ){
        if( !_enabled )
            return false; 
        
        boolean handled = false;
        
        if( action == Canvas.DOWN ){
            _selIndex++;
            
            if( _selectedSide == CMD_LEFT ){
                if( _selIndex > _leftCmdsCnt-1 ){
                    _selIndex = 1;
                }
            } else{
                if( _selIndex > _rightCmdsCnt-1 ){
                    _selIndex = 1;
                }
            }
            handled = true;
        } else if( action == Canvas.UP ){
            _selIndex--;
            
            if( _selectedSide == CMD_LEFT ){
                if( _selIndex < 1 ){
                    _selIndex = _leftCmdsCnt-1;
                }
            } else{
                if( _selIndex < 1 ){
                    _selIndex = _rightCmdsCnt-1;
                }
            }
            handled = true;
        } else if( action == Canvas.FIRE || keyCode == KeyConstants.LEFT_SOFT_BUTTON ){
            // select
            int cmdID = 0;
            if( _selectedSide == CMD_LEFT ){
                cmdID = _leftCmds[_selIndex];
            } else{
                cmdID = _rightCmds[_selIndex];
            }
            
            Event evt = EventFactory.getInstance().getEvent( Event.EVT_CMD_SELECTED, this );
            evt._value = new Integer( cmdID );
            notifySubscribers( evt );
            
            dock();
            
            handled = true;
        } else if( keyCode == KeyConstants.RIGHT_SOFT_BUTTON ){
            dock();
            handled = true;
        }
        
        return handled;
    }
    
    private boolean keyPressedDocked( int action, int keyCode ){
        if( keyCode == KeyConstants.LEFT_SOFT_BUTTON ){
            //System.err.println("keyPressedDocked... left soft key press");
            if( _leftCmdsCnt == 1 ){
                Event evt = EventFactory.getInstance().getEvent( Event.EVT_CMD_SELECTED, this );
                evt._value = new Integer( _leftCmds[0] );
                notifySubscribers( evt );
            } else{                
                show( CMD_LEFT );
            }
        } else if( keyCode == KeyConstants.RIGHT_SOFT_BUTTON ){
            //System.err.println("keyPressedDocked... right soft key press");
            if( _rightCmdsCnt == 1 ){
                Event evt = EventFactory.getInstance().getEvent( Event.EVT_CMD_SELECTED, this );
                evt._value = new Integer( _rightCmds[0] );
                notifySubscribers( evt );
            } else{
                show( CMD_RIGHT );
            }
        }
        
        return true;
    }
    
    public boolean handleKeyReleased(int action, int keyCode) {
        return false;
    }
    
    private void setState( int state ){
        _prevState = _curState;
        _curState = state;
    }  
}
